# 聚合上提张力计算
import math
from typing import List

from common.params import SoftParams
from model.soft.soft_common import AxialForceResult, data_init, UniForceResult


# 计算 f_safe_cable 最新方法
def calc_f_safe_cable(D: float, params: SoftParams, cur: AxialForceResult, pre: AxialForceResult, preN: float,
                preF: float, base_val: float) -> float:
    factor_b: float = math.cos(math.radians(pre.inclination))
    # 电缆的单位浮重
    w2: float = params.w2
    # 定义 f
    f: float = base_val
    params.L1 = round(params.L1)
    if (cur.depth >= 0) and (cur.depth < D - params.L1):
        # print("执行条件2")
        f = w2 * factor_b + params.get_mu_pull(cur.depth) * preN + preF
        # if cur.depth == 0:
        #     print("当前的深度是{}，当前的f是{}".format(cur.depth,f))
    return f


# 计算 N 最新计算方法
def calc_n(D: float, params: SoftParams, cur: AxialForceResult, F: float) -> float:
    # 电缆的单位浮重
    w2: float = params.w2
    params.L1 = round(params.L1)
    factor_a: float = cur.azimuth_rate
    factor_b: float = math.sin(math.radians(cur.inclination))
    factor_c: float = cur.inclination_rate
    # if cur.depth == 0:
    #     print("当前的深度是{}，当前的F是{}".format(cur.depth, F))

    if (cur.depth > 0) and (cur.depth <= D - params.L1):
        factor_d: float = F * factor_a * factor_b
        factor_e: float = F * factor_c
        n: float = math.sqrt(math.pow(factor_d, 2) + math.pow(factor_e + w2 * factor_b, 2))

        return n
    # return cur.N


# 计算F和N
# D 全井深
def calc_uni(D: float, params: SoftParams, cur: AxialForceResult, pre: AxialForceResult,
             _list_: List[AxialForceResult], base_val: float) -> AxialForceResult:
    cur.F_pull = calc_f_safe_cable(D, params, cur, pre, pre.N_pull, pre.F_pull, base_val)
    cur.N_pull = calc_n(D, params, cur, cur.F_pull)
    # print(JsonUtil.obj2str(cur))
    return cur


# 迭代函数
def deep_func(idx: int, params: SoftParams, _list_: List[AxialForceResult], base_val: float) -> UniForceResult:
    # 本次迭代深度
    D: float = _list_[idx].depth
    # print("本次迭代深度D",D)

    _list_[idx].F_pull = base_val
    _list_[idx].N_pull = calc_n(D, params, _list_[idx], _list_[idx].F_pull)
    # print("当前的深度是{}，当前的_list_[-1].F_pull是{}".format(_list_[idx].depth,_list_[-1].F_pull))
    result: UniForceResult = UniForceResult()
    # while low <= high:
    #     mid = (low + high) / 2
    for i in range(idx - 1, -1, -1):
        _list_[i] = calc_uni(_list_[idx].depth, params, _list_[i], _list_[i + 1], _list_, base_val)
        result.depth = D
        result.F_pull = _list_[i].F_pull
        result.N_pull = _list_[i].N_pull
        result.Q_final = base_val

        if _list_[i].depth <= 0:
            result.N_pull = _list_[i + 1].N_pull
            # print("从深度{}开始迭代".format(_list_[idx].depth - params.L1))
            # print(JsonUtil.obj2str(result))
            return result


# 聚合构建 返回计算结果
def uni_build(params: SoftParams, _list_: List[AxialForceResult], base_val: float, sc: {}, desired_depths: List[float],wellhead_friction: float) -> List[UniForceResult]:
    operatingLoad: float = params.operatingLoad / 100
    # 上下限
    range_left: float = params.F_break * params.confidence_level * 1000 * operatingLoad - wellhead_friction
    range_right: float = params.F_break * 1000 * operatingLoad - wellhead_friction
    # T 为张力
    t: List[UniForceResult] = []
    data_len = len(_list_)
    params.L1 = round(params.L1)
    # 迭代的最小深度
    dept_min: int = int(_list_[0].depth)
    # 计算所有深度点的液体阻力
    # fluid_resistances_pull = {}
    # for idx in range(data_len):
    #     fluid_resistances_pull[_list_[idx].depth] = tool_pull_fluid(params, _list_[idx])
    # 获取待迭代的深度列表
    # desired_depths = [900, 600, 300]  # 以300为间隔的前三个深度
    for depth in desired_depths:
        # 找到对应深度在 _list_ 中的索引
        idx = next((i for i, item in enumerate(_list_) if item.depth >= depth), None)
        if idx is not None:
            t_item: UniForceResult = deep_func(idx, params, _list_, base_val)
            # print(JsonUtil.obj2str(t_item))
            # 比较，如果是不在范围内 @TODO
            f_pull = t_item.F_pull
            if f_pull <= range_right and f_pull >= range_left:
                # 如果力值在范围内，则保存当前结果并继续循环
                t.append(t_item)
            else:
                # print("深度：{} 力为:{} 比较值为:{}-{}".format(t_item.depth, t_item.F_pull, range_left, range_right))
                sc['ok'] = False
                sc['depth'] = t_item.depth
                sc['f_pull'] = t_item.F_pull
                break
            # print(JsonUtil.obj2str(t_item))
    return t


def run(params: SoftParams, _list_, base_val: float, desired_depths: List[float], wellhead_friction: float) -> {}:
    # 数据预处理
    result_arr: List[AxialForceResult] = data_init(_list_)
    # 中间变量
    sc = {}
    sc['depth'] = 0.0
    sc['ok'] = True
    sc['f_pull'] = 0.0
    # 计算结果
    result: List[UniForceResult] = uni_build(params, result_arr, base_val,sc, desired_depths, wellhead_friction)
    sc['result'] = result
    return sc



